home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / net_src.arc / telunix.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-05-08  |  7.3 KB  |  342 lines

  1. #include <stdio.h>
  2. #include "global.h"
  3. #include "mbuf.h"
  4. #include "timer.h"
  5. #include "icmp.h"
  6. #include "netuser.h"
  7. #include "tcp.h"
  8. #include "telnet.h"
  9. #include "session.h"
  10.  
  11. #define TUMAXSCAN 3    /* max number of telunix clients active */
  12. #define TURQSIZ    512    /* max data we will request from pty at once */
  13.  
  14. struct tcb *tnix_tcb = NULLTCB;
  15. struct tcb *tnixtcb[TUMAXSCAN];    /* savebuf for tcb ptrs for scan routines */
  16. extern int errno;
  17.  
  18. /* Start telnet-unix server */
  19. tnix1(argc,argv)
  20. char *argv[];
  21. {
  22.     struct socket lsocket;
  23.     extern int32 ip_addr;
  24.     void tnix_state();
  25.  
  26.     /* Incoming Telnet */
  27.     lsocket.address = ip_addr;
  28.  
  29.     if(argc < 2)
  30.         lsocket.port = TELNET_PORT;
  31.     else
  32.         lsocket.port = atoi(argv[1]);
  33.  
  34.     tnix_tcb = open_tcp(&lsocket,NULLSOCK,TCP_SERVER,0,
  35.             NULLVFP,NULLVFP,tnix_state,0,(char *)NULL);
  36.  
  37.     if(tnix_tcb == NULLTCB)
  38.         fprintf(stderr,"start telunix fails rsn %d.\n",net_error);
  39.     else
  40.         log(tnix_tcb,"STARTED Telunix - (%d %x)",
  41.             lsocket.port,tnix_tcb);
  42. }
  43.  
  44. /* Shut down Telnet server */
  45. tnix0()
  46. {
  47.     if(tnix_tcb != NULLTCB) {
  48.         log(tnix_tcb,"STOPPED Telunix - (%x)",tnix_tcb);
  49.         close_tcp(tnix_tcb);
  50.     } else
  51.         fprintf(stderr,"stop telunix fails -- no server active.\n");
  52. }
  53.  
  54. /* Handle incoming Telnet-Unix connect requests */
  55. static void
  56. tnix_state(tcb,old,new)
  57. struct tcb *tcb;
  58. char old,new;
  59. {
  60.     register int i;
  61.     register struct telnet *tn;
  62.     int tnix_addscan();
  63.     extern void tnix_rmvscan();
  64.     extern int send_tcp();
  65.     extern struct mbuf *free_p();
  66.     extern int del_tcp();
  67.     extern int close_tcp();
  68.     extern void free();
  69.  
  70.     tn = (struct telnet *)tcb->user;
  71.  
  72.     switch(new){
  73.     case ESTABLISHED:
  74.         /* Create and initialize a Telnet protocol descriptor */
  75.         if((tn = (struct telnet *)calloc(1,sizeof(struct telnet))) == NULLTN){
  76.             log(tcb,"reject Telunix - no space");
  77.             sndmsg(tcb,"Rejected; no space on remote\n");
  78.             close_tcp(tcb);
  79.             return;
  80.         }
  81.         tn->session = NULLSESSION;
  82.         tn->state = TS_DATA;
  83.         tcb->user = (char *)tn;    /* Upward pointer */
  84.         tn->tcb = tcb;        /* Downward pointer */
  85.         tn->inbuf = NULLBUF;
  86.         tn->outbuf = NULLBUF;
  87.         if(tnix_addscan(tcb) < 0 ||
  88.            (tn->fd = OpenPty()) < 3) {    /* barf if <= stderr */
  89.             tnix_rmvscan(tcb);
  90.             log(tcb,"reject Telunix - no Unix ports");
  91.             sndmsg(tcb,
  92.                 "Rejected; no ports available on remote\n");
  93.             close_tcp(tcb);
  94.             return;
  95.         }
  96.         log(tcb,"open Telunix - (%d %x %d %d)",tn->fd,tcb,old,new);
  97.         break;
  98.  
  99.     case FINWAIT1:
  100.     case FINWAIT2:
  101.     case CLOSING:
  102.     case LAST_ACK:
  103.     case TIME_WAIT:
  104.         if(tn != NULLTN &&
  105.            tn->fd > 2) {
  106.             log(tcb,"close Telunix - (%d %x %d %d)",
  107.                 tn->fd,tcb,old,new);
  108.             close(tn->fd);
  109.             tn->fd = 0;
  110.         }
  111.         tnix_rmvscan(tcb);
  112.         break;
  113.  
  114.     case CLOSE_WAIT:
  115.         /* flush that last buffer */
  116.         if(tn != NULLTN &&
  117.            tn->outbuf != NULLBUF &&
  118.            tn->outbuf->cnt != 0) {
  119.             send_tcp(tcb,tn->outbuf);
  120.             tn->outbuf = NULLBUF;
  121.         }
  122.         close_tcp(tcb);
  123.         break;
  124.     
  125.     case CLOSED:
  126.         if(tn != NULLTN) {
  127.             if(tn->fd > 2) {
  128.                 log(tcb,"close Telunix - (%d %x %d %d)",
  129.                     tn->fd,tcb,old,new);
  130.                 close(tn->fd);
  131.                 tn->fd = 0;
  132.             }
  133.             if(tn->inbuf != NULLBUF)
  134.                 free_p(tn->inbuf);
  135.             if(tn->outbuf != NULLBUF)
  136.                 free_p(tn->outbuf);
  137.             free((char *)tn);
  138.         }
  139.         tnix_rmvscan(tcb);
  140.         del_tcp(tcb);
  141.         if(tcb == tnix_tcb)
  142.             tnix_tcb = NULLTCB;
  143.         break;
  144.     }
  145. }
  146.  
  147. /* Telunix io interface.  Called periodically to process any waiting io.  */
  148. void
  149. tnix_try(tcb)
  150. register struct tcb *tcb;
  151. {
  152.     extern void tnix_rmvscan();
  153.     extern int recv_tcp();
  154.     extern int send_tcp();
  155.     extern void tnix_input();
  156.  
  157.     register struct telnet *tn;
  158.     register int i;
  159.  
  160.     if((tn = (struct telnet *)tcb->user) == NULLTN || tn->fd < 3) {
  161.         /* Unknown connection - remove it from queue */
  162.         log(tcb,"error Telnet - tnix_try (%d)", tn);
  163.         tnix_rmvscan(tcb);
  164.         return;
  165.     }
  166.     /*
  167.      * First, check if there is any pending io for the pty:
  168.      */
  169.     if(tn->inbuf != NULLBUF) {
  170.         tnix_input(tn);
  171.     }
  172.     if(tn->inbuf == NULLBUF) {
  173.         if(tcb->rcvcnt > 0 &&
  174.            recv_tcp(tcb,&(tn->inbuf),0) > 0)
  175.             tnix_input(tn);
  176.     }
  177.     /*
  178.      * Next, check if there is any io for tcp:
  179.      */
  180.     do {
  181.         if(tn->outbuf == NULLBUF &&
  182.            (tn->outbuf = alloc_mbuf(TURQSIZ)) == NULLBUF)
  183.             return;        /* can't do much without a buffer */
  184.     
  185.         if(tn->outbuf->cnt < TURQSIZ) {
  186.             if((i = read(tn->fd, tn->outbuf->data + tn->outbuf->cnt,
  187.                 TURQSIZ - tn->outbuf->cnt)) == -1) {
  188.                 log(tcb,"error Telunix - read (%d %d %d)",
  189.                     errno, tn->fd,
  190.                     TURQSIZ - tn->outbuf->cnt);
  191.                 close_tcp(tcb);
  192.                 return;
  193.             }
  194.             if((tn->outbuf->cnt += i) < TURQSIZ)
  195.                 i = 0;    /* didn't fill buffer so don't retry */
  196.         } else {
  197.             i = -1;        /* any nonzero value will do */
  198.         }
  199.         if(tn->outbuf->cnt == 0 ||    /* nothing to send */
  200.            tcb->sndcnt > tcb->window)    /* too congested to send */
  201.             return;
  202.         if(send_tcp(tcb,tn->outbuf) < 0) {
  203.             log(tcb,"error Telunix - send_tcp (%d %d %d)",
  204.                 net_error, tn->fd, tn->outbuf->cnt);
  205.             close_tcp(tcb);
  206.             tn->outbuf = NULLBUF;
  207.             return;
  208.         }
  209.         tn->outbuf = NULLBUF;
  210.     } while(i);
  211. }
  212.  
  213. /* Process incoming TELNET characters */
  214. void
  215. tnix_input(tn)
  216. register struct telnet *tn;
  217. {
  218.     void doopt(),dontopt(),willopt(),wontopt(),answer();
  219.     char *memchr();
  220.     register int i;
  221.     register struct mbuf *bp;
  222.     char c;
  223.  
  224.     bp = tn->inbuf;
  225.  
  226.     /* Optimization for very common special case -- no special chars */
  227.     if(tn->state == TS_DATA){
  228.         while(bp != NULLBUF &&
  229.               memchr(bp->data,IAC,bp->cnt) == NULLCHAR) {
  230.             if((i = write(tn->fd, bp->data, bp->cnt)) == bp->cnt) {
  231.                 tn->inbuf = bp = free_mbuf(bp);
  232.             } else if(i == -1) {
  233.                 log(tn->tcb,"error Telunix - write (%d %d %d)",
  234.                     errno, tn->fd, bp->cnt);
  235.                 close_tcp(tn->tcb);
  236.                 return;
  237.             } else {
  238.                 bp->cnt -= i;
  239.                 bp->data += i;
  240.                 return;
  241.             }
  242.         }
  243.         if(bp == NULLBUF)
  244.             return;
  245.     }
  246.     while(pullup(&(tn->inbuf),&c,1) == 1){
  247.         bp = tn->inbuf;
  248.         switch(tn->state){
  249.         case TS_DATA:
  250.             if(uchar(c) == IAC){
  251.                 tn->state = TS_IAC;
  252.             } else {
  253.                 if(!tn->remote[TN_TRANSMIT_BINARY])
  254.                     c &= 0x7f;
  255.                 if(write(tn->fd, &c, 1) != 1) {
  256.                     /* we drop a character here */
  257.                     return;
  258.                 }
  259.             }
  260.             break;
  261.         case TS_IAC:
  262.             switch(uchar(c)){
  263.             case WILL:
  264.                 tn->state = TS_WILL;
  265.                 break;
  266.             case WONT:
  267.                 tn->state = TS_WONT;
  268.                 break;
  269.             case DO:
  270.                 tn->state = TS_DO;
  271.                 break;
  272.             case DONT:
  273.                 tn->state = TS_DONT;
  274.                 break;
  275.             case IAC:
  276.                 if(write(tn->fd, &c, 1) != 1) {
  277.                     /* we drop a character here */
  278.                     return;
  279.                 }
  280.                 tn->state = TS_DATA;
  281.                 break;
  282.             default:
  283.                 tn->state = TS_DATA;
  284.                 break;
  285.             }
  286.             break;
  287.         case TS_WILL:
  288.             willopt(tn,c);
  289.             tn->state = TS_DATA;
  290.             break;
  291.         case TS_WONT:
  292.             wontopt(tn,c);
  293.             tn->state = TS_DATA;
  294.             break;
  295.         case TS_DO:
  296.             doopt(tn,c);
  297.             tn->state = TS_DATA;
  298.             break;
  299.         case TS_DONT:
  300.             dontopt(tn,c);
  301.             tn->state = TS_DATA;
  302.             break;
  303.         }
  304.     }
  305. }
  306.  
  307. /* called periodically from main loop */
  308. void
  309. tnix_scan()
  310. {
  311.     void tnix_try();
  312.     register int i;
  313.  
  314.     for(i = 0; i < TUMAXSCAN; i += 1)
  315.         if(tnixtcb[i] != NULLTCB)
  316.             tnix_try(tnixtcb[i]);
  317. }
  318.  
  319. int
  320. tnix_addscan(tcb)
  321. struct tcb *tcb;
  322. {
  323.     register int i;
  324.     for(i = 0; i < TUMAXSCAN; i += 1)
  325.         if(tnixtcb[i] == NULLTCB) {
  326.             tnixtcb[i] = tcb;
  327.             return i;
  328.         }
  329.     return -1;
  330. }
  331.  
  332. void
  333. tnix_rmvscan(tcb)
  334. struct tcb *tcb;
  335. {
  336.     register int i;
  337.  
  338.     for(i = 0; i < TUMAXSCAN; i += 1)
  339.         if(tnixtcb[i] == tcb)
  340.             tnixtcb[i] = NULLTCB;
  341. }
  342.